﻿using Sidvall.Serialization;
using Sidvall.UI.Messaging;
using System.Collections.Generic;

namespace Sidvall.UI.Navigation
{
	public class NavigationManager : INavigationManager
	{
		#region Public Members

		public const string AddToHistoryParameter = "AddToHistory";

		#region CanGoBack

		public bool CanGoBack
		{
			get
			{
				return this.History.CanGoBack;
			}
		}

		#endregion
		#region CanGoForward

		public bool CanGoForward
		{
			get
			{
				return this.History.CanGoForward;
			}
		}

		#endregion
		#region CanRefresh

		public bool CanRefresh
		{
			get
			{
				return this.History.CanRefresh;
			}
		}

		#endregion
		#region CurrentHistoryItem

		public HistoryItem CurrentHistoryItem
		{
			get
			{
				return this.History.CurrentItem;
			}
		}

		#endregion
		#region CurrentNavigationAction

		private NavigationAction _CurrentNavigationAction = NavigationAction.None;
		public NavigationAction CurrentNavigationAction
		{
			get
			{
				return _CurrentNavigationAction;
			}
			private set
			{
				_CurrentNavigationAction = value;
			}
		}

		#endregion
		#region HistoryItemCount

		public int HistoryItemCount
		{
			get
			{
				return this.History.Count;
			}
		}

		#endregion
		#region MaxHistoryItemCount

		public int? MaxHistoryItemCount
		{
			get
			{
				return this.History.MaxCount;
			}
			set
			{
				this.History.MaxCount = value;
			}
		}

		#endregion

		#region AddHistoryItem

		public void AddHistoryItem(HistoryItem state)
		{
			AddHistoryItem(state, true);
		}
		public void AddHistoryItem(HistoryItem state, bool setAsCurrentSource)
		{
			if (this.CurrentNavigationAction != NavigationAction.None)
				return;
			if (!this.History.AddItem(state, setAsCurrentSource))
				return;
			OnNavigationEvent(NavigationEventType.AddedHistoryItem);
		}
		public void AddHistoryItem(HistoryRegionItem state)
		{
			if (this.CurrentNavigationAction != NavigationAction.None)
				return;
			if (!this.History.AddItem(state))
				return;
			OnNavigationEvent(NavigationEventType.AddedHistoryItem);
		}

		#endregion
		#region ClearHistoryItems

		public void ClearHistoryItems()
		{
			if (this.CurrentNavigationAction != NavigationAction.None)
				return;
			this.History.Clear();
			OnNavigationEvent(NavigationEventType.RemovedHistoryItem);
		}

		#endregion
		#region GetHistoryItem

		public HistoryItem GetHistoryItem(int index)
		{
			if (this.History.Count > index)
				return this.History[index];
			return null;
		}

		#endregion
		#region RemoveLastHistoryItem

		public void RemoveLastHistoryItem()
		{
			if (this.CurrentNavigationAction != NavigationAction.None)
				return;
			if (!this.History.RemoveLastItem())
				return;
			OnNavigationEvent(NavigationEventType.RemovedHistoryItem);
		}

		#endregion

		#region GoBack

		public void GoBack()
		{
			if (this.CurrentNavigationAction != NavigationAction.None)
				return;
			try
			{
				this.CurrentNavigationAction = NavigationAction.GoBack;
				if (!this.History.GoBack())
					return;
			}
			finally
			{
				this.CurrentNavigationAction = NavigationAction.None;
			}
			OnNavigationEvent(NavigationEventType.Navigated);
		}

		#endregion
		#region GoForward

		public void GoForward()
		{
			if (this.CurrentNavigationAction != NavigationAction.None)
				return;
			try
			{
				this.CurrentNavigationAction = NavigationAction.GoForward;
				if (!this.History.GoForward())
					return;
			}
			finally
			{
				this.CurrentNavigationAction = NavigationAction.None;
			}
			OnNavigationEvent(NavigationEventType.Navigated);
		}

		#endregion
		#region GoToPosition

		public bool GoToPosition(int index)
		{
			return GoToPosition(index, true);
		}
		public bool GoToPosition(int index, bool showViewModel)
		{
			if (this.CurrentNavigationAction != NavigationAction.None)
				return false;
			try
			{
				this.CurrentNavigationAction = NavigationAction.GoToPosition;
				if (!this.History.GoToPosition(index, showViewModel))
					return false;
			}
			finally
			{
				this.CurrentNavigationAction = NavigationAction.None;
			}
			OnNavigationEvent(NavigationEventType.Navigated);

			return true;
		}

		#endregion
		#region Refresh

		public bool Refresh()
		{
			if (this.CurrentNavigationAction != NavigationAction.None)
				return false;
			try
			{
				this.CurrentNavigationAction = NavigationAction.Refresh;
				if (!this.History.Refresh())
					return false;
			}
			finally
			{
				this.CurrentNavigationAction = NavigationAction.None;
			}
			OnNavigationEvent(NavigationEventType.Navigated);

			return true;
		}

		#endregion

		#region AddToHistory

		public static bool AddToHistory(IDictionary<string, string> index)
		{
			if (index == null)
				return true;
			if (!index.ContainsKey(AddToHistoryParameter))
				return true;
			return index[AddToHistoryParameter].ToBoolean(true);
		}

		#endregion
		#region ToString

		public override string ToString()
		{
			return "NavigationManager";
		}

		#endregion

		#endregion
		#region Private Members

		#region History

		private HistoryItemCollection _History;
		private HistoryItemCollection History
		{
			get
			{
				if (_History == null)
					_History = new HistoryItemCollection();
				return _History;
			}
		}

		#endregion

		#region OnNavigationEvent

		private void OnNavigationEvent(NavigationEventType type)
		{
			var message = new NavigationMessage(this)
			{
				NavigationEventType = type
			};
			EventManager.Publish(message);
		}

		#endregion

		#endregion
	}
}
